#include "opencv2/opencv.hpp"

typedef unsigned char Byte;

typedef struct Size
{
	int Height;
	int Width;
}Size;

typedef struct Mat
{
	Byte* data;
	Size size;
}Mat;


typedef struct Point
{
	int x;
	int y;
}Point;

Point newPoint(int x, int y)
{
	Point NewPoint;

	NewPoint.x = x;
	NewPoint.y = y;

	return NewPoint;
}

Size newSize(int height, int width)
{
	Size NewSize;

	NewSize.Height = height;
	NewSize.Width = width;

	return NewSize;
}

int GetOTSUThreshold(short* HistGray, int Amount)
{
	int i;
	int PixelBack = 0, PixelIntegralBack = 0, PixelIntegralFore = 0, PixelIntegral = 0;
	int OmegaBack = 0, OmegaFore = 0, MicroBack, MicroFore, SigmaB, Sigma;              //类间方差;
	int MinValue, MaxValue;
	int Threshold = 0;

	for (MinValue = 0; MinValue < 256 && HistGray[MinValue] == 0; MinValue++);
	for (MaxValue = 255; MaxValue > MinValue && HistGray[MaxValue] == 0; MaxValue--);

	if (MaxValue == MinValue)		//图像中只有一个颜色
	{
		return MaxValue;
	}
	if (MinValue + 1 == MaxValue)	//图像中只有二个颜色
	{
		return MinValue;
	}

	PixelIntegral = 0;
	for (i = MinValue; i <= MaxValue; i++)
	{
		PixelIntegral += (HistGray[i] << 14) / Amount * i;	//iHist[255]
	}
	SigmaB = -1;
	for (i = MinValue; i <= MaxValue; i++)
	{
		PixelBack = (HistGray[i] << 14) / Amount;			//hist[i]
		PixelIntegralBack += PixelBack * i;					//iHist[i]
		OmegaBack += PixelBack;								//wa sumHist[i]
		if(OmegaBack == 0)
		{
			OmegaBack = 1;
		}
		OmegaFore = 16384 - OmegaBack;						//wb 16384 = 1 << 14
		if(OmegaFore == 0)
		{
			OmegaFore = 1;
		}

		PixelIntegralFore = (PixelIntegral - PixelIntegralBack) / OmegaFore;//ub
		MicroBack = PixelIntegralBack / OmegaBack;			//ua
		MicroFore = PixelIntegral >> 14;					//u

		Sigma = OmegaBack * (MicroBack - MicroFore) * (MicroBack - MicroFore)
			+ OmegaFore * (PixelIntegralFore - MicroFore) * (PixelIntegralFore - MicroFore);

		if (Sigma > SigmaB)
		{
			SigmaB = Sigma;
			Threshold = i;
		}
	}
	return Threshold;
}

void GetBlockHist(const Mat SrcImg, Point Start, Size BlockSize, short* hist)
{
	int i, j;
	int step;
	Byte* ptrStart;

	memset(hist, 0, sizeof(short) * 256);
	ptrStart = SrcImg.data + Start.y * SrcImg.size.Width + Start.x;
	step = SrcImg.size.Width - BlockSize.Width;

	for (i = 0; i < BlockSize.Height; i++)
	{
		for (j = 0; j < BlockSize.Width; j++)
		{
			hist[*(ptrStart++)]++;
		}
		ptrStart += step;
	}

	return;
}

int Gray2bwOTSU(const Mat SrcImg, Mat* DstImg, int scale)
{
	int i;
	short HistGray[256];
	int Threshold = 0;
	int Amount = SrcImg.size.Height * SrcImg.size.Width;
	Byte *ptrSrc, *ptrDst;

	memset(HistGray, 0, sizeof(short) * 256);
	GetBlockHist(SrcImg, newPoint(0, 0), SrcImg.size, HistGray);
	Threshold = GetOTSUThreshold(HistGray, Amount);
	Threshold = (Threshold * scale) >> 8;
	//根据阈值二值化
	ptrSrc = SrcImg.data;
	ptrDst = DstImg->data;
	for (i = 0; i < Amount; i++)
	{
		*(ptrDst++) = (*(ptrSrc++) <= Threshold);
	}

	DstImg->size = SrcImg.size;
	return Threshold;
}

int doubleZoneMatch(const Mat BWImg, int dir)
{
	int i = 0, j = 0;
	int whitePoint1 = 0, whitePoint2 = 0;
	int half_width = BWImg.size.Width / 2;
	int half_height = BWImg.size.Height / 2;
	Byte *ptr;
	Byte *BWminiImage = new Byte[BWImg.size.Width*BWImg.size.Width];

	ptr = BWImg.data;
	for (i = 0; i < BWImg.size.Height; i++)
	{
		for (j = 0; j < BWImg.size.Width; j++)
		{
			if (dir == 0)
			{
				if (j < half_width)
				{
					whitePoint1 += *ptr++;
				}
				else
				{
					whitePoint2 += *ptr++;
				}
			}
			else if (dir == 1)
			{
				if (i < half_height)
				{
					whitePoint1 += *ptr++;
				}
				else
				{
					whitePoint2 += *ptr++;
				}
			}
			else
			{
				if ((BWImg.size.Height * i + BWImg.size.Width * j
					- BWImg.size.Height * BWImg.size.Width) <= 0)
				{
					whitePoint1 += *ptr++;
				}
				else
				{
					whitePoint2 += *ptr++;
				}
			}
		}
	}

	delete [] BWminiImage;
	if (dir == 3)
		return whitePoint1 + whitePoint2;
	printf("............%d,%d\n",whitePoint1,whitePoint2);
	return whitePoint1 - whitePoint2;
}

int main(void)
{
    cv::Mat srcImg = cv::imread("2020.bmp",0);
    //设置空矩阵用于保存目标图像
	cv::Mat resImg;
    cv::resize(srcImg, resImg, cv::Size(200,100));
    // roi
    cv::Rect rect(73,30,17,40);
    cv::Mat roi = resImg(rect);
    
    Mat GrayImg, BWImg;
    Byte Graydata[2000];
	Byte BWdata[2000];
    GrayImg.data = Graydata;
	BWImg.data = BWdata;
    
    GrayImg.size = newSize(40, 17);
    memcpy(GrayImg.data,roi.data,40*17);
    BWImg.size = newSize(40, 17);
	
    Gray2bwOTSU(GrayImg, &BWImg, 100);
    int diffRegion = doubleZoneMatch(BWImg, 1);
    printf("diffRegion:-------------------------:%d\n",diffRegion);
    cv::imwrite("test.bmp",roi);
    return 0;
}
